package hk.com.fgoproduction.getdroplets.Activity

import android.Manifest
import android.app.Activity
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Environment
import android.support.v4.app.ActivityCompat
import android.util.Log
import com.alibaba.fastjson.JSON
import com.dropbox.core.v2.files.FileMetadata
import com.dropbox.core.v2.files.Metadata
import hk.com.fgoproduction.getdroplets.BroadcastAndNoti.NotiReceiver
import hk.com.fgoproduction.getdroplets.DropboxAPI.AFile
import hk.com.fgoproduction.getdroplets.Lib.Common.AdaptiveStorage.StorageApiWrapper
import hk.com.fgoproduction.getdroplets.Lib.Common.ThisApplication
import hk.com.fgoproduction.getdroplets.Lib.Common.ToolInstance.CheckConnection
import hk.com.fgoproduction.getdroplets.Lib.Common.ToolInstance.LogInstance
import hk.com.fgoproduction.getdroplets.Lib.Common.ToolInstance.RuntimePermissions
import hk.com.fgoproduction.getdroplets.Lib.Common.ToolInstance.ToastInstance
import hk.com.fgoproduction.getdroplets.Lib.DB.FileRevBean
import hk.com.fgoproduction.getdroplets.Lib.DB.FileRevBeanGp
import hk.com.fgoproduction.getdroplets.Lib.DB.FileRevDb
import hk.com.fgoproduction.getdroplets.Lib.OAuth.TokenResult
import hk.com.fgoproduction.getdroplets.R
import hk.com.fgoproduction.getdroplets.Service.AutoSyncJob
import kotlinx.android.synthetic.main.activity_main.*
import org.jetbrains.anko.collections.forEachByIndex
import org.jetbrains.anko.toast

class MainActivity : Activity() {

    private val showLog = true
    private val DL_FILE_CODE = 200
    private val START_TAG = 401
    private val OFFLINE_FLAG = 999
    private val CACHE_FLAG = 1234
    private val TOKEN = lazy{resources.getString(R.string.token)}

    private val CONFIG = lazy{getSharedPreferences(resources.getString(R.string.config), MODE_PRIVATE)}
    private val interval = lazy{ CONFIG.value.getLong("interval", 1000*60*60*1) }

    private val dlTest = lazy { obj.downloadFile("/com.amaze.filemanager_29.apk") }
    private val share = lazy { getSharedPreferences(TOKEN.value, MODE_PRIVATE) }

    private lateinit var obj: AFile
    private var isFail = false

    private lateinit var testJobService: JobScheduler
    private var jobId = 1000
    private lateinit var receiver: NotiReceiver

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        if (!CheckConnection.isOnline(this@MainActivity))
            startActivityForResult(Intent(this@MainActivity, ReconnectActivity::class.java), OFFLINE_FLAG)
        else {
            obj = (application as ThisApplication).fileApiFactory(this)
            if (share.value.contains("access")) {
                if (share.value.getString("access", null) != null) {
                    testAccessToken()
                    if (!isFail)
                        initialization()
                } else
                    getAccessToken()
            } else {
                //timeLog = System.currentTimeMillis()
                getAccessToken()
            }
        }
    }

    private fun getAccessToken() {
        startActivityForResult(Intent(this@MainActivity, OAuthActivity::class.java), START_TAG)
    }

    private fun testAccessToken() {
        try {
            dropboxStatus()
        } catch (e: Exception) {
            e.printStackTrace()
            isFail = true
            getAccessToken()
        }
    }

    //Initialize the view after access token is confirmed
    private fun initialization() {
        setContentView(R.layout.activity_main)
        btnList()
        text1.text = share.value.getString("access", null)
        NotiReceiver.clearInstance()
        receiver = NotiReceiver.receiverFactory(this, IntentFilter())

        testJobService = application.getSystemService(Context.JOB_SCHEDULER_SERVICE) as JobScheduler

        checkPermission()
    }

    private fun checkPermission() {
        if (RuntimePermissions.shouldAskForPermissions(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
            ActivityCompat.requestPermissions(this, Array(1) { Manifest.permission.WRITE_EXTERNAL_STORAGE }, DL_FILE_CODE)
        }
    }

    //initialize view btn
    private fun btnList() {
        var list: List<Metadata>? = null

        getFolderListBtn.setOnClickListener {
            (application as ThisApplication).runOnBg(Runnable {
                list = obj.getFolderList().entries
            })
            list?.forEachByIndex {
                if (it is FileMetadata) {
                    Log.d("$this", it.name + " - " + it.serverModified.toString())
                }
            }
//      startService(Intent(this, FileVerValService::class.java))
        }

        ulBtn.setOnClickListener {
//            val tempFile = File.createTempFile("todo", ".md")
//            tempFile.deleteOnExit()
//            val out = FileOutputStream(tempFile)
//            IOUtil.copyStreamToStream(assets.open("todo.md"), out)
//            val path = (tempFile.absolutePath)
            val prefix = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
            val list = (application as ThisApplication).filePathQueue
            prefix.listFiles().forEach {
                list.add(it.absolutePath)
            }

            receiver.startListening(NotiReceiver.NOTI_TAG_IO)
            val bundle = Bundle()
            bundle.putInt("id", 1)
            bundle.putByte("dl", 0)

            val intent = Intent(NotiReceiver.NOTI_TAG_IO)
            intent.putExtras(bundle)
            sendBroadcast(intent)
        }

        dlBtn.setOnClickListener {
            //startDownload()
            //Use service to download file
            receiver.startListening(NotiReceiver.NOTI_TAG_IO)
            val list = (application as ThisApplication).filePathQueue
            (application as ThisApplication).runOnBgAndJoin(Runnable {
                obj.getFolderList("/pixiv").entries.forEach {
                    if (it is FileMetadata)
                        list.add(it.pathLower)
                }
            })

            val bundle = Bundle()
            bundle.putByte("dl", 1)
            bundle.putInt("id", 1)

            val intent = Intent(NotiReceiver.NOTI_TAG_IO)
            intent.putExtras(bundle)
            sendBroadcast(intent)
        }

        localFileBtn.setOnClickListener {
            checkPermission()
            startActivity(Intent(this@MainActivity, LocalFileManActivity::class.java))
        }

        upBtn.text = "Dropbox file man"
        upBtn.setOnClickListener {
            startActivity(Intent(this@MainActivity, DropboxManAct::class.java))
        }

        storageBtn.setOnClickListener {
            checkPermission()
            val path = StorageApiWrapper.getRemovableExternalStorageDirectory()
            if (path !== null) {
                val intent = Intent(this@MainActivity, LocalFileManActivity::class.java)
                intent.putExtra("path", path)
                startActivity(intent)
            } else {
                toast("Fail!")
            }
        }

        serviceStartBtn.setOnClickListener{
            if (!(application as ThisApplication).jobSchedulerList.contains(jobId)) {
                val builder = JobInfo.Builder(jobId, ComponentName(this, AutoSyncJob::class.java))
                (application as ThisApplication).jobSchedulerList.add(jobId)

                val job = builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)
//                        .setRequiresDeviceIdle(true)
//                        .setPeriodic(interval.value)
                        //.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)           //Any network
                        //.setRequiresCharging(true)
                        .setOverrideDeadline(1000*60*2)
                        .build()
                testJobService.schedule(job)
            }
        }

        serviceStopBtn.setOnClickListener {
            if ((application as ThisApplication).jobSchedulerList.size != 0) {

                val id = (application as ThisApplication).jobSchedulerList[0]
                testJobService.cancel(id)
                (application as ThisApplication).jobSchedulerList.remove(id)
            } else {
                testJobService.cancelAll()
            }
        }

        verBtn.setOnClickListener {
            receiver.startListening(NotiReceiver.NOTI_TAG_VER)
            val intent = Intent(NotiReceiver.NOTI_TAG_VER)
            intent.putExtra("path", "/pixiv")
            intent.putExtra("localPath", Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).absolutePath)
            sendBroadcast(intent)
        }

        testDbBtn.setOnClickListener {
            val db = FileRevDb.FileRevDbFactory(this)
            db.create("test")
            db.init("test")

            val bean = FileRevBean()
            bean.fullPath = "/abc/123.png"
            bean.name = "123.png"
            bean.rev = "6a351sd6851"

            val bean2 = FileRevBean()
            bean2.fullPath = "/def/456.jpg"
            bean2.name = "456.jpg"
            bean2.rev = "iu654ser234"

            val beanList = FileRevBeanGp()
            beanList.list.add(bean)
            beanList.list.add(bean2)

            db.put(beanList)
            Log.d("db", db.get(bean2.fullPath)?.fullPath)
        }

        clearDb.setOnClickListener {
            deleteFile("test")
        }
    }

    override fun onDestroy() {
        if (receiver.isListening)
            receiver.stopListening()
        NotiReceiver.clearInstance()
        super.onDestroy()
    }

    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (resultCode != RESULT_OK) {
            toast("Fail!")
            finish()
        } else {
            if (requestCode == START_TAG) {
                addTokenToSP(extractToken(data))

                if (!isFail)
                    initialization()
                else {
                    isFail = false
                    restartActivity()
                }
            } else if (requestCode == OFFLINE_FLAG) {
                restartActivity()
            }
        }
    }

    private fun addTokenToSP(token: String) {
        val editor = share.value.edit()
        editor.putString("access", token)
        editor.apply()
    }

    private fun extractToken(data: Intent?) : String {

        val result = data!!.getStringExtra("result")
        LogInstance.log("Result", result, LogInstance.LogType.DEBUG, showLog)

        return JSON.parseObject(result, TokenResult::class.java).access_token
    }

    private fun restartActivity() {
        finish()
        startActivity(intent)
    }

    private fun startDownload() {
        (application as ThisApplication).runOnBg(Runnable {
            dlTest.value
        })
    }

    /**
     * For SDK VER>=23, new permission framework is introduced and works with Runtime Confirmation.
     */
    override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>?, grantResults: IntArray?) {
        if (requestCode == DL_FILE_CODE) {
            if (grantResults?.size == 1 && grantResults?.get(0) == PackageManager.PERMISSION_GRANTED) {
                //threadExec(Runnable { startDownload() })
            } else {
                ToastInstance.show(this, "Action Cancelled!")
            }
        }
    }

    /**
     * Testing function to ensure the connection to Dropbox is normal
     */
    private fun dropboxStatus() {
        try {
            threadExec(Runnable { obj.isDropboxOk() })
        } catch(e: Exception) {
            if (CheckConnection.isOnline(this)) {
                throw e
            } else {
                startActivityForResult(Intent(this@MainActivity, ReconnectActivity::class.java), OFFLINE_FLAG)
            }
        }
    }

    private fun threadExec(runnable: Runnable) {
        (application as ThisApplication).runOnBgAndJoin(runnable)
    }

}
